package cn.lg.soar.redis.config;

import cn.lg.soar.common.algorithm.serial.Snowflake;
import cn.lg.soar.core.config.cache.ICacheManagerSupplier;
import cn.lg.soar.core.config.cache.template.ICacheTemplate;
import cn.lg.soar.core.manager.IStateAccessTokenManager;
import cn.lg.soar.core.model.AccessTokenProps;
import cn.lg.soar.redis.cache.*;
import cn.lg.soar.redis.cache.template.CacheTemplateRedis;
import cn.lg.soar.redis.cache.template.CacheTemplateRedisByteArray;
import cn.lg.soar.redis.cache.template.CacheTemplateRedisString;
import cn.lg.soar.redis.manager.RedisStateAccessTokenManager;
import cn.lg.soar.redis.model.CacheEvictMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;

import java.util.List;

/**
 * redis配置类
 * @Author: lgx
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
@Configuration
@ConditionalOnProperty(value = "lg.redis.enabled", havingValue = "true", matchIfMissing = true)
public class CacheConfig {

    @Autowired
    private RedisTemplate<String, Object> redis;
    @Autowired
    private RedisTemplate<String, byte[]> byteRedisTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private AccessTokenProps accessTokenProps;

    @Value("${lg.cache.enabled-evict-broadcast:false}")
    private Boolean enabledEvictBroadcast;

    @Value("${spring.application.name:soar}")
    private String applicationName;

    private final String topic =  "-cache-evict";
    private final Long id = Snowflake.nextValue();

    @Primary
    @Bean
    public ICacheTemplate<String, Object> cacheTemplate(){
        return new CacheTemplateRedis(redis);
    }

    @Primary
    @Bean
    public ICacheTemplate<String, byte[]> byteArrayCacheTemplate(){
        return new CacheTemplateRedisByteArray(byteRedisTemplate);
    }

    @Primary
    @Bean
    public ICacheTemplate<String, String> stringCacheTemplate(){
        return new CacheTemplateRedisString(stringRedisTemplate);
    }

    @Primary
    @Bean
    public ICacheManagerSupplier cacheManagerSupplier(){
        return new CacheManagerRedisSupplier();
    }

    @Primary
    @Bean
    public IStateAccessTokenManager redisStateAccessTokenManager() {
        return new RedisStateAccessTokenManager(accessTokenProps, redis);
    }

    @Bean
    public CacheEvictPublisher cacheEvictPublisher() {
        if (enabledEvictBroadcast) {
            return new PubSubCacheEvictPublisher(id, applicationName + topic);
        }
        return new CacheEvictPublisher() {
            @Override
            public void publish(List<CacheEvictMessage> cacheEvicts) {}
            @Override
            public void publish(CacheEvictMessage item) {}
        };
    }

    @Bean
    @ConditionalOnProperty(name = "lg.cache.enabled-evict-broadcast", havingValue = "true")
    public RedisMessageListenerContainer pubsubEvictMode(RedisConnectionFactory connectionFactory, SoarCacheManager soarCacheManager) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        // 订阅
        container.addMessageListener(
                new PubSubCacheEvictListener(id, applicationName + topic, soarCacheManager),
                new ChannelTopic(applicationName + topic)
        );
        return container;
    }

}
